package com.yuqingxin.redisCacheApi.common.redisCache;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuqingxin.redisCacheApi.entity.ApiScheduleEntity;
import com.yuqingxin.redisCacheApi.mapper.ApiScheduleMapper;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.Executor;

/**
 * @author yuqingxin
 * 自定义接口缓存注解RedisCache的切面
 * */
@Aspect
@Component
@Log4j2
public class RedisCacheAspect {

    @Autowired
    private RedisCacheService redisCacheService;

    @Autowired
    private Executor threadPool;

    @Autowired
    private ApiActiveService apiActiveService;

    @Autowired
    private ApiScheduleMapper apiScheduleMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Around("@annotation(redisCache)")
    public Object getControllerData(ProceedingJoinPoint joinPoint, RedisCache redisCache) throws Throwable {
         //采用前端Header入参方式判断调用该方法的方式
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String isActive = null;
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            isActive = request.getHeader("isActive");
        }

        //获取方法的相关信息
        String className = joinPoint.getTarget().getClass().getName();
        String arguments = objectMapper.writeValueAsString(joinPoint.getArgs());
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String methodName = method.getName();
        String argumentsType = Arrays.toString(method.getParameterTypes());

        // 构建缓存键：类名 + 方法 + 参数值
        String key = className + ":" + methodName + ":" + arguments;
        String result = redisCacheService.get(key);
        log.info("RedisCache:{}",result);
        if (result == null) {
            //调用接口逻辑并获取对应的返回数据并转换为字符串
            result =  objectMapper.writeValueAsString(joinPoint.proceed());
            log.info("set RedisCache:{} :: {}",key,result);
            redisCacheService.set(key, result, redisCache.timeout(),redisCache.timeUnit());
        }

        //非主动调用时->更新redis数据
        if (null == isActive){
            threadPool.execute(()-> {
                try {
                    String updateResult = objectMapper.writeValueAsString(joinPoint.proceed());
                    log.info("Set RedisCache:{} :: {}", key, updateResult);
                    redisCacheService.set(key, updateResult, redisCache.timeout(), redisCache.timeUnit());
                } catch (Throwable e) {
                    log.error("Set RedisCache Error:{}", key);
                    e.printStackTrace();
                }
            });
        }

        //把记录更新到api缓存表
        String finalIsActive = isActive;
        threadPool.execute(()->{
            LocalDateTime now = LocalDateTime.now();
            LambdaQueryWrapper<ApiScheduleEntity> asL = new LambdaQueryWrapper<>();
            asL.eq(ApiScheduleEntity::getClassName,className)
                    .eq(ApiScheduleEntity::getMethodName,method.getName())
                    .eq(ApiScheduleEntity::getArgumentsType,argumentsType)
                    .eq(ApiScheduleEntity::getArguments,arguments);
            ApiScheduleEntity apiSchedule = apiScheduleMapper.selectOne(asL);
            if (apiSchedule != null){
                apiSchedule.setUpdateAt(now);
                //主动调用 则 更新 主动调用时间
                if ("1".equals(finalIsActive)){
                    apiSchedule.setLastActiveTime(now);
                }

                //适配cron更改的情况
                apiSchedule.setCron(redisCache.cron());

                if (1 != apiSchedule.getStatus()){
                    apiSchedule.setStatus(1);
                    //添加对应的定时任务
                    log.info("addApiScheduledTask:{}"+key);
                    apiActiveService.addApiScheduledTask(apiSchedule);
                }
                apiScheduleMapper.updateById(apiSchedule);
            }else {
                ApiScheduleEntity apiScheduleEntity = new ApiScheduleEntity();
                apiScheduleEntity.setClassName(className);
                apiScheduleEntity.setMethodName(method.getName());
                apiScheduleEntity.setArgumentsType(argumentsType);
                apiScheduleEntity.setArguments(arguments);
                apiScheduleEntity.setCron(redisCache.cron());
                apiScheduleEntity.setLastActiveTime(now);
                apiScheduleEntity.setUpdateAt(now);
                apiScheduleMapper.insert(apiScheduleEntity);

                //添加对应的定时任务
                log.info("addApiScheduledTask:{}"+key);
                apiActiveService.addApiScheduledTask(apiScheduleEntity);
            }
        });
        //把获取到的字符串转化为接口的返回类型
        return objectMapper.readValue(result,method.getReturnType());
    }
}
